home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / program / misc / mkdepend.lha / MkDepend-1.0 / reader.c < prev   
C/C++ Source or Header  |  1995-09-14  |  11KB  |  522 lines

  1. /*
  2. $VER: reader:c 1.0 (13-Sep-95) Copyright © by Lars Düning
  3. */
  4.  
  5. /*---------------------------------------------------------------------------
  6. ** Reading of C-Sources and filter for #include statements.
  7. ** Also here are routines for the modification of Makefiles.
  8. **
  9. ** Copyright © 1995  Lars Düning  -  All rights reserved.
  10. ** Permission granted for non-commercial use.
  11. **---------------------------------------------------------------------------
  12. ** Credits:
  13. **   The buffering scheme was inspired by the input module of lcc (by
  14. **   Chris Fraser & David Hanson).
  15. **---------------------------------------------------------------------------
  16. ** C: DICE 3.01
  17. **---------------------------------------------------------------------------
  18. ** [lars] Lars Düning; Am Wendenwehr 25; D-38114-Braunschweig;
  19. **                     Germany; Tel. 49-531-345692
  20. **---------------------------------------------------------------------------
  21. ** 10-Sep-95 [lars] v 1.0
  22. ** 13-Sep-95 [lars] current
  23. **---------------------------------------------------------------------------
  24. */
  25.  
  26. #include <assert.h>
  27. #include <fcntl.h>
  28. #include <string.h>
  29. #include <sys/types.h>
  30. #include "reader.h"
  31.  
  32. /*-------------------------------------------------------------------------*/
  33.  
  34. #define BUFSIZE 10240              /* Size of the file buffer */
  35. static char   aBuffer[BUFSIZE+1];  /* File buffer */
  36. static int    fdFile;              /* Filehandle */
  37. static int    fdFile2;             /* Filehandle Writer */
  38. static char * pLimit;              /* Pointer to closing sentinel in buffer */
  39. static char * pch;                 /* Pointer to actual char in buffer */
  40. static char * pIName;              /* Start of include filename */
  41.  
  42. #define END_OF_BUF()  (pch >= pLimit)
  43. #define END_OF_FILE() (pLimit == aBuffer)
  44.  
  45. /*-------------------------------------------------------------------------*/
  46. void
  47. reader_init (void)
  48.  
  49. /* Initialize the reader.
  50.  */
  51.  
  52. {
  53.   fdFile = -1;
  54.   fdFile2 = -1;
  55.   aBuffer[BUFSIZE] = '\n';
  56.   pLimit = aBuffer+BUFSIZE;
  57.   pch = pLimit;
  58.   pIName = NULL;
  59. }
  60.  
  61. /*-------------------------------------------------------------------------*/
  62. static int
  63. fillbuffer (void)
  64.  
  65. /* Read in the next chunk from file such that incrementing pch will
  66.  * access the newly read data.
  67.  *
  68.  * Result:
  69.  *   0 on success, non-0 else (errno holds error code then).
  70.  *   pch is set to the start of the new data.
  71.  */
  72.  
  73. {
  74.   int iRead;
  75.  
  76.   if (END_OF_FILE())
  77.     return 1;
  78.   if (pIName)
  79.   {
  80.     if (pch > pLimit)
  81.       pch = pLimit;
  82.     memcpy(aBuffer, pIName, pLimit-pIName);
  83.     pch -= (pLimit-pIName);
  84.   }
  85.   else
  86.     pch = aBuffer;
  87.   iRead = read(fdFile, pch, aBuffer+BUFSIZE-pch);
  88.   if (iRead >= 0)
  89.   {
  90.     pLimit = pch+iRead;
  91.     *pLimit = '\n';
  92.   }
  93.   return iRead < 0;
  94. }
  95.  
  96. /*-------------------------------------------------------------------------*/
  97. int
  98. reader_open (const char *pName)
  99.  
  100. /* Open a file for reading.
  101.  *
  102.  *   pName: Name of the file to read.
  103.  *
  104.  * Result:
  105.  *   0 on success, non-0 else (errno contains error code then).
  106.  *
  107.  * The reader is initialized to read and filter the file name *pName.
  108.  */
  109.  
  110. {
  111.   assert(pName);
  112.   assert(fdFile < 0);
  113.   reader_init();
  114.   fdFile = open(pName, O_RDONLY);
  115.   return fdFile >= 0;
  116. }
  117.  
  118. /*-------------------------------------------------------------------------*/
  119. int
  120. reader_openrw (const char *pNameR, const char *pNameW)
  121.  
  122. /* Open two makefiles for modification.
  123.  *
  124.  *   pNameR: Name of the file to read, may be NULL.
  125.  *   pNameW: Name of the file to read.
  126.  *
  127.  * Result:
  128.  *   0 on success, non-0 else (errno contains error code then).
  129.  *
  130.  * The reader is initialized to read the old makefile *pNameR and writing
  131.  * of new makefile *pNameW.
  132.  */
  133.  
  134. {
  135.   assert(pNameW);
  136.   assert(fdFile < 0);
  137.   assert(fdFile2 < 0);
  138.   reader_init();
  139.   fdFile2 = open(pNameW, O_WRONLY|O_CREAT|O_TRUNC);
  140.   if (fdFile2 < 0)
  141.     return 1;
  142.   if (pNameR)
  143.   {
  144.     fdFile = open(pNameR, O_RDONLY);
  145.     if (fdFile < 0)
  146.     {
  147.       close(fdFile2);
  148.       fdFile2 = -1;
  149.     }
  150.   }
  151.   return fdFile2 < 0;
  152. }
  153.  
  154. /*-------------------------------------------------------------------------*/
  155. int
  156. reader_close (void)
  157.  
  158. /* Close the file currently read.
  159.  * Result:
  160.  *   0 on success, non-0 else.
  161.  *   errno set to error code in case.
  162.  */
  163.  
  164. {
  165.   int i;
  166.  
  167.   i = 0;
  168.   if (fdFile >= 0)
  169.   {
  170.     i = close(fdFile);
  171.   }
  172.   fdFile = -1;
  173.   if (fdFile2 >= 0)
  174.   {
  175.     i = close(fdFile2) || i;
  176.   }
  177.   fdFile = -1;
  178.   return i;
  179. }
  180.  
  181. /*-------------------------------------------------------------------------*/
  182. int
  183. reader_eof (void)
  184.  
  185. /* Test if the file read is at its end.
  186.  *
  187.  * Result:
  188.  *   Non-0 on end of file.
  189.  */
  190.  
  191. {
  192.   return END_OF_FILE();
  193. }
  194.  
  195. /*-------------------------------------------------------------------------*/
  196. const char *
  197. reader_get (void)
  198.  
  199. /* Extract the next include statement from the file being read.
  200.  *
  201.  * Result:
  202.  *   Pointer to the filename extracted from the statement, or NULL on error
  203.  *     or end of file.
  204.  *     The memory is property of reader_get(), the pointer valid just until
  205.  *     the next call to reader_get().
  206.  *   errno set to an error code in case.
  207.  */
  208.  
  209. {
  210.   enum { StartOfLine, InLine, FoundHash, SkipComment, SkipLComment, FoundInclude
  211.       }  eState;
  212.   char   *stab[]
  213.     = {
  214.         "Start "
  215.       , "InLine"
  216.       , "Found#"
  217.       , "SkipC "
  218.       , "SkipLC"
  219.       , "FoundI"
  220.       };
  221.   char   ch;
  222.   int    iFound; /* Number of chars found of "include" */
  223.   int    bDone;
  224.  
  225. #define GETCHAR() \
  226.   ch = *pch++; \
  227.   if (ch == '\n' && pch >= pLimit) \
  228.   { \
  229.     if (fillbuffer()) { \
  230.       pIName = NULL; \
  231.       return NULL; \
  232.     } \
  233.     ch = *pch++; \
  234.   }
  235.  
  236.   if (pIName)
  237.     eState = InLine;
  238.   else
  239.     eState = StartOfLine;
  240.   pIName = NULL;
  241.  
  242.   bDone = 0;
  243.   while (!bDone)
  244.   {
  245.     /* Get the next interesting non-linefeed character */
  246.     do {
  247.       GETCHAR()
  248.       if (ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f')
  249.       {
  250.         eState = StartOfLine;
  251.         pIName = NULL;
  252.       }
  253.       else
  254.         break;
  255.     } while (1);
  256.  
  257.     switch(eState)
  258.     {
  259.     case StartOfLine:
  260.       switch (ch)
  261.       {
  262.       case '#':
  263.         eState = FoundHash;
  264.         iFound = 0;
  265.         break;
  266.       case '/':
  267.         GETCHAR()
  268.         if (ch == '/')
  269.           eState = SkipLComment;
  270.         else if (ch == '*')
  271.           eState = SkipComment;
  272.         else
  273.           eState = InLine;
  274.         break;
  275.       case ' ': case '\t':
  276.         /* still: eState = StartOfLine; */
  277.         break;
  278.       default:
  279.         eState = InLine;
  280.         break;
  281.       }
  282.       break;
  283.  
  284.     case InLine:
  285.       switch (ch)
  286.       {
  287.       case '/':
  288.         GETCHAR()
  289.         if (ch == '/')
  290.           eState = SkipLComment;
  291.         else if (ch == '*')
  292.           eState = SkipComment;
  293.         else
  294.           eState = InLine;
  295.         break;
  296.       case '\\':
  297.         GETCHAR()
  298.         /* still: eState = InLine; */
  299.         break;
  300.       default:
  301.         /* still: eState = InLine; */
  302.         break;
  303.       }
  304.       break;
  305.  
  306.     case FoundHash:
  307.       switch(ch)
  308.       {
  309.       case ' ': case '\t':
  310.         if (iFound)
  311.         {
  312.           eState = InLine;
  313.           iFound = 0;
  314.         }
  315.         /* else still: eState = FoundHash */
  316.         break;
  317.       case 'i': case 'n': case 'c': case 'l':
  318.       case 'u': case 'd': case 'e':
  319.         if ("include"[iFound] != ch)
  320.         {
  321.           eState = InLine;
  322.           iFound = 0;
  323.         }
  324.         else if (ch == 'e')
  325.         {
  326.           eState = FoundInclude;
  327.           pIName = NULL;
  328.         }
  329.         else
  330.           iFound++;
  331.         break;
  332.       default:
  333.         eState = InLine;
  334.       }
  335.       break;
  336.  
  337.     case FoundInclude:
  338.       switch(ch)
  339.       {
  340.       case ' ': case '\t':
  341.         /* still: eState = FoundInclude */
  342.         break;
  343.       case '<':
  344.         if (!pIName)
  345.         {
  346.           eState = InLine;
  347.         }
  348.         break;
  349.       case '"':
  350.         if (!pIName)
  351.         {
  352.           pIName = pch;
  353.         }
  354.         else
  355.         {
  356.           *(pch-1) = '\0';
  357.           if (pch-1 == pIName)
  358.             pIName = NULL;
  359.           else
  360.             bDone = 1;
  361.           eState = InLine;
  362.         }
  363.         break;
  364.  
  365.       default:
  366.         if (!pIName)
  367.           eState = InLine;
  368.         break;
  369.       }
  370.       break;
  371.  
  372.     } /* switch (eState) */
  373.  
  374.     /* Skip comments immediately */
  375.     if (eState == SkipComment)
  376.     {
  377.       while(1) {
  378.         do {
  379.           GETCHAR()
  380.         } while (ch != '*');
  381.         GETCHAR()
  382.         if (ch == '/')
  383.         break;
  384.       }
  385.       eState = StartOfLine;
  386.     }
  387.     else if (eState == SkipLComment)
  388.     {
  389.       do {
  390.         GETCHAR()
  391.       } while (ch != '\n' && ch != '\r' && ch != '\v' && ch != '\f');
  392.       eState = StartOfLine;
  393.     }
  394.   } /* while(!bDone) */
  395.   return pIName;
  396.  
  397. #undef GETCHAR
  398. }
  399.  
  400. /*-------------------------------------------------------------------------*/
  401. int
  402. reader_writeflush (void)
  403.  
  404. /* Write out the buffer to the written makefile.
  405.  * Return 0 on success, non-0 else (errno holds the error code then).
  406.  */
  407.  
  408. {
  409.   if (pch > aBuffer && write(fdFile2, aBuffer, pch-aBuffer) != pch-aBuffer)
  410.     return 1;
  411.   pch = aBuffer;
  412.   return 0;
  413. }
  414.  
  415. /*-------------------------------------------------------------------------*/
  416. int
  417. reader_writen (const char *pText, int len)
  418.  
  419. /* Append the first <len> characters of <pText> to the written file.
  420.  * Return 0 on success, non-0 else (errno holds the error code then)
  421.  */
  422.  
  423. {
  424.   assert(pText);
  425.   assert(fdFile2 >= 0);
  426.   if (pLimit-pch < len && reader_writeflush())
  427.     return 1;
  428.   memcpy(pch, pText, len);
  429.   pch += len;
  430.   return 0;
  431. }
  432.  
  433. /*-------------------------------------------------------------------------*/
  434. int
  435. reader_write (const char *pText)
  436.  
  437. /* Append <pText> to the written file.
  438.  * Return 0 on success, non-0 else (errno holds the error code then)
  439.  */
  440.  
  441. {
  442.   return reader_writen(pText, strlen(pText));
  443. }
  444.  
  445. /*-------------------------------------------------------------------------*/
  446. int
  447. reader_copymake (const char * pTagline)
  448.  
  449. /* Copy the file from fdFile to fdFile2 up to including the tagline.
  450.  * If the tagline is not found, it is appended.
  451.  * The tagline MUST end in a newline character!
  452.  * Return 0 on success, non-0 on error (errno holds the error code then).
  453.  */
  454.  
  455. {
  456.   int len;
  457.   int count; /* Next charactor to compare in pTagline, or -1 if to skip
  458.               * up to the next Newline */
  459.   char ch;
  460.  
  461.  
  462.   assert(pTagline);
  463.   assert(fdFile2);
  464.   len = strlen(pTagline);
  465.   assert(len < 120);
  466.  
  467.   /* Simplest case: no old makefile to copy */
  468.   if (fdFile < 0)
  469.   {
  470.     strcpy(aBuffer, pTagline);
  471.     pch = aBuffer+len;
  472.     return 0;
  473.   }
  474.   if (fillbuffer())
  475.     return 1;
  476.   count = 0;
  477.  
  478.   while (!END_OF_FILE() && count < len)
  479.   {
  480.     if (END_OF_BUF())
  481.     {
  482.       if (write(fdFile2, aBuffer, pch-aBuffer) != pch-aBuffer)
  483.         return 1;
  484.       if (fillbuffer())
  485.         return 1;
  486.       if (END_OF_FILE())
  487.         break;
  488.     }
  489.     ch = *pch;
  490.     if (count < 0)
  491.     {
  492.       if (ch == '\n')
  493.         count = 0;
  494.     }
  495.     else
  496.     {
  497.       if (ch == pTagline[count])
  498.         count++;
  499.       else if (ch == '\n')
  500.         count = 0;
  501.       else
  502.         count = -1;
  503.     }
  504.     pch++;
  505.   }
  506.  
  507.   /* Switch to write mode */
  508.   pLimit = aBuffer+BUFSIZE;
  509.  
  510.   /* Append a newline if missing */
  511.   if (count < 0 && reader_writen("\n", 1))
  512.     return 1;
  513.  
  514.   /* Put the Tagline into the buffer if necessary */
  515.   if (count < len && reader_writen(pTagline, len))
  516.     return 1;
  517.  
  518.   return 0;
  519. }
  520.  
  521. /***************************************************************************/
  522.